/***************************************************************
 * Name:      CoreStructs.h
 * Purpose:   Defines the Core algorithm Structures used in GanitSheets
 * Author:    Milind Gupta (milind.gupta@gmail.com)
 * Website:   https://code.google.com/p/ganitsheets/
 * Created:   2011-03-08
 * Copyright: Milind Gupta ()
 * License:   Apache License 2.0
 **************************************************************/

#ifndef __GS_CORESTRUCTS_H
#define __GS_CORESTRUCTS_H

#include "Globals.h"
#include <string>

struct shtSize
{
    unsigned int rows;
    unsigned int columns;
};

struct retPacket
{
    std::string message;
    enum packetReturnCodes
    {
        ERR,
        SUCCESS
    };
    enum packetReturnCodes returnCode;
    unsigned short int returnSubCode;
};

template <class LISTITEM> class listIterator;
template <class LISTITEM> class listManager;

template <class LISTITEM>
class listManager
{
    public:
        listManager();
        ~listManager();
        LISTITEM *AddItem();
        bool RemoveItem(LISTITEM *item);
        listIterator<LISTITEM> *getIterator();
        bool removeIterator(listIterator<LISTITEM> *iter);
        friend class listIterator<LISTITEM>;
        unsigned int numOfItems();
        unsigned int numOfIters();
    protected:
        unsigned int itemCount;
        unsigned int iterCount;
        class structListItem
        {
            public:
                structListItem *prevStruct;
                structListItem *nextStruct;
                LISTITEM *currItem;
                structListItem();
                ~structListItem();
        };
        class iterListItem  // To define the list of iterators
        {
            public:
                iterListItem *prevIter;
                iterListItem *nextIter;
                listIterator<LISTITEM> *currIter;
                iterListItem();
                ~iterListItem();
        };
        iterListItem *iterators;
        structListItem *firstStructList;
        structListItem *lastStructList;
};

template <class LISTITEM>
class listIterator
{
    public:
        listIterator(listManager<LISTITEM> *listMngr);
        LISTITEM *nextStructListItem();     // Function to return the next LISTITEM
        LISTITEM *prevStructListItem();     // Function to return the previous LISTITEM
        LISTITEM *currStructListItem();     // Function to return the current LISTITEM
        void pointToStart();            // Point the currListItem pointer so that nextStructListItem gives the firstStructList Item
        void pointToEnd();              // Point the currListItem pointer to the lastStructList item
    private:
        class listManager<LISTITEM> *myList;
        class listManager<LISTITEM>::structListItem *currStructList;
};

// List Manager Constructor
template <class LISTITEM>
listManager<LISTITEM>::listManager()
{
    this->firstStructList = 0;
    this->lastStructList = 0;
    this->iterators = 0;
    this->itemCount = 0;
    this->iterCount = 0;
}

// List Manager Destructor
template <class LISTITEM>
listManager<LISTITEM>::~listManager()
{
    // Delete all structListItem objects and the associated LISTITEMs
    if(this->firstStructList!=0)
    {
        // Delete the structListItem objects here
        while(this->firstStructList->nextStruct!=0)
        {
            this->firstStructList = this->firstStructList->nextStruct;
            this->firstStructList->prevStruct->nextStruct = 0;
            delete this->firstStructList->prevStruct;
            this->firstStructList->prevStruct = 0;
        }
        delete this->firstStructList;
        this->firstStructList = 0;
        this->lastStructList = 0;
    }
    // Delete all iterList and listIterator objects
    // Rewind the iterator list
    while(this->iterators->prevIter)
        this->iterators = this->iterators->prevIter;
    while(iterators->nextIter)
    {
        this->iterators = this->iterators->nextIter;
        this->iterators->prevIter->nextIter = 0;
        delete this->iterators->prevIter;
        this->iterators->prevIter = 0;
    }
    delete this->iterators;
}

template <class LISTITEM>
unsigned int listManager<LISTITEM>::numOfItems()
{
    return this->itemCount;
}

template <class LISTITEM>
unsigned int listManager<LISTITEM>::numOfIters()
{
    return this->iterCount;
}

// To create a new LISTITEM in the listManager
template <class LISTITEM>
LISTITEM *listManager<LISTITEM>::AddItem()
{
    this->itemCount = this->itemCount + 1;
    if(this->lastStructList == 0)
    {
        this->lastStructList = new structListItem;
        this->lastStructList->currItem = new LISTITEM;
        this->firstStructList = this->lastStructList;
        return this->firstStructList->currItem;
    }
    else
    {
        structListItem *tempStructListItem;
        tempStructListItem = new structListItem;
        tempStructListItem->currItem = new LISTITEM;
        this->lastStructList->nextStruct = tempStructListItem;
        tempStructListItem->prevStruct = this->lastStructList;
        this->lastStructList = tempStructListItem;
        return tempStructListItem->currItem;
    }
}

// This function returns the iterator to the listManager
template <class LISTITEM>
class listIterator<LISTITEM> *listManager<LISTITEM>::getIterator()
{
    listIterator<LISTITEM> *iter;
    iter = new listIterator<LISTITEM>(this);
    this->iterCount = this->iterCount + 1;
    // Add this iterator to the list of iterators for this object
    if(this->iterators==0)
    {
        // This is the first iterator
        this->iterators = new iterListItem;
    }
    else
    {
        // Add the iterator to the iterators linked list
        this->iterators->nextIter = new iterListItem;
        this->iterators->nextIter->prevIter = this->iterators;
        this->iterators = this->iterators->nextIter;
    }
    this->iterators->currIter = iter;
    return iter;
}

template <class LISTITEM>
bool listManager<LISTITEM>::RemoveItem(LISTITEM *item)
{
    if(!item)
        return false;
    structListItem *itemIter;
    itemIter = this->firstStructList;
    while(itemIter->currItem!=item)
    {
        itemIter = itemIter->nextStruct;
        if(!itemIter)
            break;
    }
    if(itemIter)
    {
        // found the match
        if(itemIter->prevStruct)
        {
            if(itemIter->nextStruct)
            {
                // Previous and next both exist
                itemIter->prevStruct->nextStruct = itemIter->nextStruct;
                itemIter->nextStruct->prevStruct = itemIter->prevStruct;
            }
            else    // Only previous exists
                itemIter->prevStruct->nextStruct = 0;
            if(this->lastStructList==itemIter) // If the main pointer was here then move it
                this->lastStructList = itemIter->prevStruct;
        }
        else if(itemIter->nextStruct)
        {
            // Only next exists
            itemIter->nextStruct->prevStruct = 0;
            if(this->firstStructList == itemIter)
                this->firstStructList = itemIter->nextStruct;
        }
        else
        {
            // Neither next nor prev exists
            this->firstStructList = 0;
            this->lastStructList = 0;
        }
        delete itemIter;
        this->itemCount = this->itemCount - 1;
        return true;
    }   // if(itemIter) ends
    return false;
}

// To remove the specified item
// To remove the specified iterator
template <class LISTITEM>
bool listManager<LISTITEM>::removeIterator(listIterator<LISTITEM> *iter)
{
    if(!iter)
        return false;
    iterListItem *loopIter;
    loopIter = this->iterators;
    // rewind the iterators linked list pointer
    while(loopIter->prevIter)
        loopIter = loopIter->prevIter;
    while(loopIter->currIter!=iter)
    {
        loopIter = loopIter->nextIter;
        if(!loopIter)
            break;
    }
    if(loopIter)
    {
        // Found the match
        if(loopIter->prevIter)
        {
            if(loopIter->nextIter)
            {
                // Previous and next both exist
                loopIter->prevIter->nextIter = loopIter->nextIter;
                loopIter->nextIter->prevIter = loopIter->prevIter;
            }
            else    // Only previous exists
                loopIter->prevIter->nextIter = 0;
            if(iterators==loopIter) // If the main pointer was here then move it
                iterators = iterators->prevIter;
        }
        else if(loopIter->nextIter)
        {
            // Only next exists
            loopIter->nextIter->prevIter = 0;
            if(iterators==loopIter)
                iterators = iterators->nextIter;
        }
        else
            // Neither next nor prev exists
            iterators = 0;
        delete loopIter;
        this->iterCount = this->iterCount - 1;
        return true;
    }
    return false;
}

template <class LISTITEM>
listManager<LISTITEM>::structListItem::structListItem()
{
    this->currItem = 0;
    this->nextStruct = 0;
    this->prevStruct = 0;
}

template <class LISTITEM>
listManager<LISTITEM>::structListItem::~structListItem()
{
    delete this->currItem;
}

template <class LISTITEM>
listManager<LISTITEM>::iterListItem::iterListItem()
{
    this->prevIter = 0;
    this->nextIter = 0;
    this->currIter = 0;
}

template <class LISTITEM>
listManager<LISTITEM>::iterListItem::~iterListItem()
{
    delete this->currIter;
}

// Constructor for listIterator
template <class LISTITEM>
listIterator<LISTITEM>::listIterator(listManager<LISTITEM> *listMngr)
{
    this->currStructList = 0;   // To point to the Struct List Item before first
    this->myList = listMngr;
}

// Function to return the next LISTITEM
template <class LISTITEM>
LISTITEM *listIterator<LISTITEM>::nextStructListItem()
{
    if(this->currStructList==0)
    {
        // Pointer is before the first
        if(this->myList->firstStructList==0)
            return 0;   // No elements
        this->currStructList = this->myList->firstStructList;
    }
    else
    {
        if(this->currStructList->nextStruct==0)
            return 0;   // Pointer at the end
        this->currStructList = this->currStructList->nextStruct;
    }
    return this->currStructList->currItem;
}

// Function to return the previous LISTITEM
template <class LISTITEM>
LISTITEM *listIterator<LISTITEM>::prevStructListItem()
{
    if(this->currStructList==0)
        return 0;   // Pointer is before the first
    if(this->currStructList->prevStruct==0)
        return 0;   // Pointer at 1st
    this->currStructList = this->currStructList->prevStruct;
    return this->currStructList->currItem;
}

// Function to return the current LISTITEM
template <class LISTITEM>
LISTITEM *listIterator<LISTITEM>::currStructListItem()
{
    if(this->currStructList==0)
        return 0;
    return this->currStructList->currItem;
}

// Point the currStructListItem pointer so that nextStructListItem gives the first struct
template <class LISTITEM>
void listIterator<LISTITEM>::pointToStart()
{
    this->currStructList = 0;
}

// Point the currStructListItem pointer to the last Struct Item
template <class LISTITEM>
void listIterator<LISTITEM>::pointToEnd()
{
    this->currStructList = this->myList->lastStructList;
}

#endif

